//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "elatypes.h"
#include "bufcache.h"
#include "fat.h"
#include "misc.h"
#include <llist.h>
#include "abc.h"

/*
 * stob()
 *    Convert sectors to bytes
 */
__inline UInt32 BufCache::
stob(UInt32 nsec)
{
    return (nsec << p_Sharedata->secshift);
}

BufCache::BufCache(fatfs_sharedata* pSharedata):m_nRef(0), p_Sharedata(pSharedata)
{
    m_freeList = NULL;
}

BufCache::~BufCache()
{
    struct buf *pBuf = NULL;
    UInt32 len = 0;
    while (pBuf = m_freeList) {
        /*
         *As a buf had been freed, b_list connect the free list
         */
        m_freeList = (struct buf *)pBuf->b_list;
        assert(pBuf && pBuf->b_data);
        len = stob(pBuf->b_nsec);
        free(pBuf->b_data);
        Ktfs_Term_Lock(&pBuf->b_lock);
        if (pBuf->b_handles) {
            free(pBuf->b_handles);
        }
        free(pBuf);
    }
}

UInt32 BufCache::AddRef()
{
    return InterlockedIncrement((PInt32)&m_nRef);
}

UInt32  BufCache::Release()
{
    UInt32 Refs;

    Refs = InterlockedDecrement((PInt32)&m_nRef);
    if (Refs == 0) {
        delete this;
    }
    return Refs;
}

struct buf * BufCache::Get(UInt32 nsec)
{
    struct buf *ret = NULL;
    UInt32 size = 0;
/*
 * If freeList is not empty, then pick one out , otherwise create
   a new buf
 */
    if (m_freeList) {
        ret = m_freeList;
        m_freeList = (struct buf*)ret->b_list;
        assert(ret);
    }
    else {
        ret = (struct buf *)malloc(sizeof(struct buf));
        if (NULL == ret) {
            return NULL;
        }

        /*
         * Get the buffer space
         */
        size = stob(nsec);
        ret->b_data = malloc(size);
        if (NULL == ret->b_data) {
            free(ret);
            return NULL;
        }
        Ktfs_Init_Lock(&ret->b_lock);
    }
    return ret;
}

void BufCache::Put(struct buf *buf)
{
    if (NULL == buf)
        return;

    buf->b_list = (struct llist *)m_freeList;
    m_freeList = buf;
}
